package middleware.p2p;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import middleware.p2p.log.MiddlewareLogEvent;
import middleware.p2p.log.VectorClock;

import org.apache.log4j.Logger;

/**
 * 	Classe implementante un Proxy per il TQueueManager.
 * 	La classe offre le funzionalità dell'oggetto remoto TQueueManager mascherando all'utilizzatore 
 * 	la complessità della comunicazione via Socket.
 * 	@see TQueue
 * 	@see TQueueManager
 */
public class TQueueManagerProxy implements TQueue {
	/**
	 * 	Indirizzo sul quale contattare l'oggetto TQueueManager remoto.
	 */
	private Address addr;
	/**
	 * 	Costruttore di default della classe.
	 */
	public TQueueManagerProxy() {
		this.addr=null;
	}
	/**
	 * 	Metodo per ottenere l'indirizzo dell'oggetto remoto con cui si sta dialogando.
	 * 	@return L'indirizzo dell'oggetto remoto.
	 * 	@see Address
	 */
	public Address getAddr() {
		return addr;
	}
	/**
	 * 	Metodo per impostare l'indirizzo del'oggetto remoto con cui dialogare.
	 * 	@param 	addr	L'indirizzo dell'oggetto remoto.
	 */
	public void setAddr(Address addr) {
		this.addr = addr;
	}	
	/**
	 * 	Metodo per eseguire il dequeue dalla coda remota.
	 * 	Questo metodo non è implementato in questa classe in quanto viene utilizzata solo per eseguire l'enqueue.
	 * 	@return Sempre null
	 */
	@Override
	public TaskDescriptor dequeue() {		
		return null;
	}

	/**
	 * 	Metodo per eseguire l'enqueue sull'oggetto TQueueManager remoto.
	 * 	Questo metodo si occupa di serializzare il task descriptor e di trasferire il file in modalità PUSH.
	 * 	@param	ts	Il task descriptor da inserire in coda.
	 * 	@return 1 se l'elemento è stato inserito, 0 altrimenti
	 */
	@Override
	public int enqueue(TaskDescriptor ts) {
		Logger log=Logger.getLogger(this.getClass());
		if (this.addr!=null) {
			try {
				TaskDescriptor baseLinkTs=new TaskDescriptor();
				baseLinkTs.setID(ts.getID());
				baseLinkTs.setCommand(ts.getCommand());
				baseLinkTs.setType(ts.getType());
				File tLink=new File(ts.getLink());				
				baseLinkTs.setLink(tLink.getName());
				Socket outSock= new Socket(this.addr.getIP(), this.addr.getPort());
				log.debug("Socket open to "+this.addr.getIP()+":"+this.addr.getPort());
				OutputStream outSockStream=outSock.getOutputStream();				
				ObjectOutputStream outStream=new ObjectOutputStream(outSockStream);
				VectorClock logLocalClock=CORE.getLogVectorClock().addEventToClock(CORE.getComponentId());
				VectorClock monitorLocalClock=CORE.getMonitorVectorClock().clone();
				MiddlewareMessage msg=MiddlewareMessage.createEmptyMessage(logLocalClock,monitorLocalClock,baseLinkTs);
				outStream.writeObject(msg);				
				log.info(new MiddlewareLogEvent(msg.getLogVclock(),
						"TaskDescriptor "+baseLinkTs.getID()+" sent to "+this.addr.getIP()+":"+this.addr.getPort()));
				FileInputStream inFile=new FileInputStream(ts.getLink());				
				byte buffer[] = new byte[256];		
				int byte_read;
				while ((byte_read=inFile.read(buffer))!=-1) {
					outSockStream.write(buffer, 0, byte_read);
					outSockStream.flush();
				}
				logLocalClock=CORE.getLogVectorClock().addEventToClock(CORE.getComponentId());
				log.info(new MiddlewareLogEvent(logLocalClock,"File "+ts.getLink()+" sent to "+this.addr.getIP()+":"+this.addr.getPort()));
				inFile.close();
				outStream.close();
				outSockStream.close();
				//outSock.close();
				return 1;
			} catch (UnknownHostException uhe) {
				uhe.printStackTrace();
				log.error(uhe,uhe);
				return 0;
			} catch (IOException ioe) {
				ioe.printStackTrace();
				log.error(ioe,ioe);
				return 0;
			}
		} else {
			return 0;
		}
	}
}
